
.model small
.stack
.data

;		Mensajes de impresion		;
msgIng	 db	 10,13,"Ingrese la base de su numero: O-Octal, H-Hexa, Q-Salir: $"
msgOctal db  10,13,"Ingrese un numero en octal (<177777): $"
msgHexa  db  10,13,"Ingrese un numero en hexadecimal (<FFFF): $"
msgErr	 db  10,13,"Opcion invalida!$"
msgErrN  db  10,13,"Numero invalido!$"
enOctal  db  10,13,"El numero en base Octal: $"
enHexa   db  10,13,"El numero en base Hexadecimal: $"

;		variables		;
cadOctal db  6 dup('0'),'$' 
cadHexa  db  4 dup ('0'),'$'
result   db  7 dup (0),'$'
base     dw  ?
opcion	 db	 ?
numVal   dw  'S'

.code

start:
	mov	 ax,@data		
	mov	 ds,ax
	
getOpcio:

	call inicial			; Inicializa las variables correspondientes ; 

	lea	 dx,msgIng			; "Ingrese la base de su numero: O-Octal, H-Hexa, Q-Salir: " ;
	mov	 ah,9		
	int	 21h

	mov	 ah,1				; Lectura de la opcion ingresada ;
	int	 21h
	mov	 opcion,al	

	cmp	 opcion,'O'			; Numero octal ;
	je	 baseO

	cmp	 opcion,'o'			; Numero octal ;
	je	 baseO
	
	cmp	 opcion,'H'			; Numero hexadecimal ;
	je	 baseH
	
	cmp	 opcion,'h'			; Numero hexadecimal ;
	je	 baseH
	
	cmp	 opcion,'Q'	        ; Salir ;
	je	 salir

	cmp	 opcion,'q'			; Salir ;
	je	 salir
	
	lea	 dx,msgErr		   	; "Opcion invalida!" ;
	mov	 ah,9		
	int	 21h
	
	jmp  getOpcio			; Lectura de otra opcion ;
	
;		Opcion hexadecimal		;
baseH:
	call getHexa			; cadHexa = numero en Hexa ;
	cmp  numVal,'N'			; Numero no valido? ;
	je   numNoVal			; Numero no es valido ;
	call hexANum			; AX = cadHexa en formato bpf;
	mov  base,8				; base = octal ;
	call cambBase			; result = numero en Octal ;
	
	lea	 dx,enOctal			; "El numero en base Octal: " ;
	mov	 ah,9
	int	 21h
	
	call impOctal			; Imprime el numero en result ;
	jmp  getOpcio			; Lectura de otra opcion ;
	
;		Opcion hexadecimal		;
baseO:
	call getOctal			; cadOctal = numero en Octal ;
	cmp  numVal,'N'			; Numero no valido? ;
	je   numNoVal			; Numero no es valido ;
	call octANum			; AX = cadOctal en formato bpf;
	mov  base,16			; base = Hexadecimal ;
	call cambBase			; result = numero en Hexadecimal ;
	
	lea	 dx,enHexa			; "El numero en base Hexadecimal: " ;
	mov	 ah,9
	int	 21h
	
	call impHexa			; Imprime el numero en result ;
	jmp  getOpcio			; Lectura de otra opcion ;

;		numero ingresado no es valido		;
numNoVal:
    lea	 dx,msgErrN			; "Numero invalido!$" ;
	mov	 ah,9
	int	 21h
	
    jmp  getOpcio			; Lectura de otra opcion ;

;		Fin del programa		;
salir:
	mov	 ax,4c00h
	int	 21h
	
;************************************;
;Recibe el numero en el registro AX  ;
;Recibe la base en 'base'            ;
;Carga el numero en la nueva base en ;
;result                              ;
;************************************;

cambBase:
	mov  dx,0				; DX = 0 ;
	mov  si,6				; SI = 6 -> result[6] ;
otraDiv:
	div  base			    ; AX / base ;
	mov  result[si],dl		; result[si] = resto division ;
	
	dec  si					; SI = SI - 1 ;
	
	cmp  ax,base			; cociente division > base ? ;
	jl   finDiv				; AX < base -> Fin de la division ;
	
	mov  dx,0				; DX = 0 -> resto = 0 ;
	jmp  otraDiv			; Division succesiva ;
finDiv:
	mov  result[si],al		; result[si] = ultimo resultado de la division ;
ret
	
	
;************************************;
;                                    ;
;Carga el numero ingresado en cadHexa;
;                                    ;
;************************************;

getHexa:
	lea	 dx,msgHexa			; "Ingrese un numero en hexadecimal (<FFFF): " ;
	mov	 ah,9
	int	 21h
	
	mov  cx,4				; CX = 4 -> 4 digitos maximo Hexa posible ;
	mov  si,0				; SI = 0 ;
otroHexa:
    mov  ax,0				; AX = 0 ;
	mov	 ah,1				; Lectura de digito ;
	int	 21h
	
	cmp  al,13				; digito = enter ? ;
    je   finHex				; Fin ingreso ;
	
	cmp  al,'0'				; digito < '0' ;
	jl   hexNoVal			; Hexa no es valido;
	
	cmp  al,':'				; digito <= '9' ;
	jl   cargaHex			; digito valido ;
	
	cmp  al,'A'				; digito < 'A' ;
	jl   hexNoVal			; Hexa no es valido ;
	
	cmp  al,'G'				; digito <= 'F' ;
	jl   cargaHex			; digito valido ;
	
	cmp  al,'a'				; digito < 'a' ;
	jl   hexNoVal			; Hexa no es valido ;
	
	cmp  al, 'g'			; digito <= 'f' ;
	jl   cargaHex			; digito valido ;
	
	jmp  hexNoVal			; Hexa no es valido ;
	
cargaHex:
	mov  cadHexa[si],al		; cadHexa[si] = digito ingresado en ASCII ;
	inc  si					; SI = SI + 1 ;
	loop otroHexa			; CX = CX - 1, si CX>0 -> lectura de otro digito ;
	
finHex:
	mov  cadHexa[si],'$'	; cadHexa[si] = cierre de string ;
	ret
hexNoVal:
	mov  numVal,'N'			; Bandera valida = N ;
	ret
	
;************************************;
;Pasa el valor de la cadena y lo     ;
;almacena en AX                      ;
;************************************;
	
hexANum:
	mov  si,0				; SI = 0 ;
	mov  ax,0				; AX = 0 ;
hexSig:
	cmp  cadHexa[si],'$'	; cadHexa[si] = cierre string ? ;
	je   hexFin				; Fin ;
	cmp  cadHexa[si],':'	; cadHexa[si] = numero decimal ? ;
	jl   hexSub0			; cadHexa[si] = cadHexa[si] - '0' ;
	cmp  cadHexa[si],'G'	; cadHexa[si] = numero alfabetico mayuscula ? ;
	jl   hexSub1			; cadHexa[si] = cadHexa[si] - 'A' + 10 ;
	cmp  cadHexa[si],'g'	; cadHexa[si] = numero alfabetico minuscula ? ;
	jl   hexSub2			; cadHexa[si] = cadHexa[si] - 'a' + 10 ;
sumVolve:
	mov  bx,16				; BX = base hexadecimal ;
	mul  bx					; AX * BX ;
	add  al,cadHexa[si] 	; AX = AX + cadHexa[si]
	inc  si					; SI = SI + 1 ;
	jmp hexSig				; Otro digito hexadecimal ;
hexSub0:
	sub  cadHexa[si],'0'
	jmp  sumVolve
hexSub1:
	sub  cadHexa[si],'A'
	add  cadHexa[si],10
	jmp  sumVolve
hexSub2:
	sub  cadHexa[si],'a'
	add  cadHexa[si],10
	jmp  sumVolve
hexFin:
	ret						; Fin, AX = numero en BPF ;
	
	
;************************************;
;imprime el valor de resultado como  ;
;Octal                               ;
;************************************;

impOctal:
	mov  si,1				; SI = 1, evita imprimir 0 inecesario ;
seguirO:
	cmp  result[si],'$'		; result[si] = Cierre string ? ;
	je   finResul			; imprimir result en ASCII ;
	add  result[si],'0'		; result[si] = result[si] + '0' -> Formato ASCII ;
	inc  si					; SI = SI + 1 ;
	jmp  seguirO			; Otro numero a modificar ;
finResul:
	lea	 dx,result			; Imprimir resultado ;
	mov	 ah,9
	int	 21h	
	ret
	
;*************************************;
;                                     ;
;Carga el numero ingresado en cadOctal;
;                                     ;
;*************************************;


getOctal:
	lea	 dx,msgOctal		; "Ingrese un numero en octal (<177777): " ;
	mov	 ah,9
	int	 21h
	
    mov  cx,6				; CX = 6 -> Max digitos octal posibles ;
	mov  si,0				; SI = 0 ;
otroOcta:
    mov  ax,0				; AX = 0 ; 
	mov	 ah,1				; Lectura de digito ;
	int	 21h

    cmp  al,13				; digito = enter ? ;
    je   finOctal			; Fin ingreso ;
	
	cmp  al,'7'				; digito > 7 ? ;
	jg   octNoVal			; numero no valido ;
	
	cmp  al,'0'				; digito < 0 ? ;
	jl   octNoVal			; numero no valido ; 
	
	sub  al,'0'				; digito valido -> AL = digito - '0' ;
	mov  cadOctal[si],al	; cadOctal[si] = numero octal ;
	
	inc  si					; SI = SI + 1 ;
	loop otroOcta			; Lectura de otro digito ;
	
	cmp  cadOctal[0],1		; cadOctal[0] > 1 ? ;
	jg   octNoVal			; Numero no es valido ;

finOctal:
	mov  cadOctal[si],'$'	; cadOctal[6] = cierre string ;
	ret
octNoVal:
	mov  numVal,'N'			; bandera valido = N ;
	ret

;************************************;
;Pasa el valor de la cadena y lo     ;
;almacena en AX                      ;
;************************************;

octANum:
	mov  si,0				; SI = 0 ;
	mov  ax,0				; AX = 0 ;
octSig:
	cmp  cadOctal[si],'$'	; cadOctal[si] = cierre string ;
	je   octFin				; Fin ;
	mov  bx,8				; BX = base octal ;
	mul  bx					; AX * BX ;
	add  al,cadOctal[si] 	; AX = AX + cadOctal[si] ;
	inc  si					; SI = SI + 1 ;
	jmp  octSig				; Otro numero octal ;
octFin:
	ret						; Fin -> AX = numero en formato BPF ;
	
;************************************;
;imprime el valor de resultado como  ;
;Hexadecimal                         ;
;************************************;	

impHexa:
	mov  si,3				; SI = 3 -> evitar imprimir ceros inecesarios ;
seguirH:
	cmp  result[si],'$'		; result[si] = cierre string ;
	je   finResuH			; Fin ;
	add  result[si],'0'		; result[si] = numero en bpf + '0' -> paso a ASCII ;
	cmp  result[si],'9'		; result[si] >= 9 ? ;
	jg   sumaA				; result[si] = numero ASCII + 7 -> ASCII alfabetico ;
volver:
	inc  si					; SI = SI + 1 ;
	jmp  seguirH			; Otro numero Hexadecimal ;
finResuH:
	lea	 dx,result			; Imprimir el numero Hexadecimal ;
	mov	 ah,9
	int	 21h	
	ret
sumaA:
	add  result[si],7	
	jmp  volver
	
;************************************;
;inicializa los valores              ;
;                                    ;
;************************************;		
	
inicial:
	mov  si,0				; SI = 0 ;
	mov  numVal,'S'			; bandera valido = S ;
segInRes:					; Inicializa result ;
	cmp  result[si],'$'		
	je   finInRes
	mov  result[si],0
	inc  si
	jmp  segInRes
finInRes:
	mov  si,0
segInOct:					; Inicializa cadOctal ;
	cmp  cadOctal[si],'$'
	je   finInOct
	mov  cadOctal[si],'0'
	inc  si
	jmp  segInOct
finInOct:
	mov  si,0
segInHex:					; Inicializa cadHexa ;
	cmp  cadHexa[si],'$'
	je   finInHex
	mov  cadHexa[si],'0'
	inc  si
	jmp  segInHex
finInHex:
	ret
end start


